feat(ui): improve cross-platform server diagnostics - #643
Conversation
Add a shared Settings Info card for the effective CodeNomad listener mode, bind host, local and remote URLs, workspace root, and candidate network addresses. Keep the Remote Access shortcut capability-gated so the same view remains useful in Electron, Tauri, and remote web sessions without exposing mutable server arguments. Clarify that per-workspace PID and port details belong to the OpenCode process, extend downloadable diagnostics with connectivity data and a privacy notice, and use the existing clipboard fallback for insecure remote contexts. Failed metadata requests now release the shared pending request so refresh can recover. Add focused formatter and retry regression tests, run them in PR validation, and translate all new labels across the nine supported locales.
pascalandr
left a comment
There was a problem hiding this comment.
Gatekeeper review — FAIL
-
Medium: specific-interface bindings produce false diagnostics
packages/ui/src/components/settings/info-settings-section.tsx:251-255,279-294
packages/ui/src/components/settings/info-settings-diagnostics.ts:25-36
With valid--host 192.168.1.20, the card reports “All network interfaces” and includeshttps://127.0.0.1:<remotePort>as a candidate. The HTTPS listener is bound only to192.168.1.20, so that loopback URL is unreachable. This misstates exposure and undermines troubleshooting.
Minimal correction: derive a “Specific interface” presentation for concrete non-loopback hosts and exclude loopback candidates in that mode from both UI and exported reports. Add a concrete-host regression test. -
Medium: insecure-context copy loses keyboard focus
packages/ui/src/components/settings/info-settings-section.tsx:170-175
packages/ui/src/lib/clipboard.ts:35-48
Remote HTTP sessions now use the shared fallback, which focuses a temporary textarea and removes it without restoring focus. Successful copying leaves keyboard and screen-reader users at the document body; exceptions can leave the temporary element behind.
Minimal correction: preserve and restore the active element, make the textarea read-only, and remove it infinally.
Validation: focused tests passed (3/3), UI typecheck and build passed, git diff --check passed, locale key parity was verified, and the PR’s Linux/Windows test jobs passed.
|
PR builds are available as GitHub Actions artifacts: https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/31385174375 Artifacts expire in 7 days.
|
Distinguish concrete bind hosts from wildcard all-interface listeners and remove unreachable loopback candidates from both the connectivity card and exported diagnostics. Add the specific-interface label to every supported locale and cover the concrete-host case. Harden the shared insecure-context clipboard fallback by keeping its temporary textarea read-only, cleaning it up on every exit path, and restoring keyboard focus. Add focused success and failure cleanup tests to PR validation. Validated with root typechecks, the UI production build, six focused tests, locale parity checks, and git diff --check.
pascalandr
left a comment
There was a problem hiding this comment.
Gatekeeper re-review — FAIL
-
Medium: concrete loopback binds still advertise unreachable listener candidates.
packages/ui/src/components/settings/info-settings-diagnostics.ts:11-19
packages/ui/src/components/settings/info-settings-section.tsx:252-295
packages/ui/src/components/settings/info-settings-diagnostics.test.ts:56-67
Filtering only applies when the derived mode isspecific. A valid--host 127.0.0.2remainslocal, preserving both127.0.0.1and127.0.0.2candidates. A Windows socket probe confirmed that a listener bound to127.0.0.2was unreachable through127.0.0.1. The card and exported report therefore still expose an unreachable loopback URL.
Minimal correction: classify wildcard versus concrete binding independently of the display mode, retain only addresses compatible with a concrete bind host, and add non-default IPv4 and IPv6 loopback tests. -
Medium: valid IPv6 bind hosts produce incorrect diagnostics.
packages/ui/src/components/settings/info-settings-diagnostics.ts:11-19,38-50
packages/ui/src/components/settings/info-settings-section.tsx:252-295
packages/server/src/index.ts:553-591
packages/server/src/server/network-addresses.ts:20-60
Raw IPv6 hosts are interpolated without URL brackets, producing malformed values such ashttps://:::9898; IPv6 interfaces are not included in candidates; and the expanded wildcard0:0:0:0:0:0:0:0is labeled “Specific network interface,” understating exposure.
Minimal correction: normalize wildcard forms, bracket IPv6 literals when constructing URLs, resolve matching IPv6 candidates, and cover::,::1, expanded wildcard, and concrete IPv6 hosts.
The clipboard fallback now restores focus and removes its textarea on success, false returns, and exceptions. Metadata retry/deduplication, privacy messaging, accessibility behavior, nine-locale key parity, test isolation, and CI wiring showed no additional actionable defects.
Validation: complete 27-file PR diff and surrounding listener code reviewed; 6 focused tests passed; all 176 CI-wired UI tests and UI typecheck passed; 1,577-key locale parity verified; Linux and Windows test jobs passed; git diff --check passed; worktree remained unchanged.
Centralize wildcard, loopback, and URL-host handling so concrete loopback bindings advertise only the address that is actually listening. Preserve exact loopback hosts for plugin URLs and make HTTPS respect the configured host rather than silently rebinding to 127.0.0.1. Add IPv6 interface enumeration and bracketed URL generation for compact, expanded wildcard, loopback, and concrete addresses. Generated certificates now treat IPv6 values as IP SANs, while metadata, CORS, and UI diagnostics share consistent listener semantics. Cover host classification, concrete candidates, IPv6 wildcard enumeration, plugin URLs, certificate SANs, and defensive UI filtering. Server/UI typechecks, the UI build, 26 focused tests, and git diff checks pass; the full local server suite has one unrelated default-branch assertion failure in git-worktrees.test.ts.
pascalandr
left a comment
There was a problem hiding this comment.
Gatekeeper re-review — FAIL
-
High: IPv6 wildcard HTTPS advertises a plugin URL rejected by its generated certificate.
packages/server/src/server/listener-base-url.ts:16-23
packages/server/src/server/tls.ts:70-79,233-247
packages/server/src/workspaces/manager.ts:402-423
Default HTTPS-only--host ::publisheshttps://[::1]:<port>to OpenCode, but the generated certificate contains onlyDNS:localhostandIP:127.0.0.1. TLS verification fails, breaking plugin-to-server communication. Existing generated certificates are also reused until expiration, so corrected SAN requirements would not reach upgrades.
Minimal correction: include::1for IPv6 wildcard certificates and rotate the leaf certificate whenever required host/configured SANs are absent. Cover fresh and reused configuration directories. -
Medium: IPv6 wildcard diagnostics omit reachable IPv4 addresses.
packages/server/src/server/http-server.ts:345-348
packages/server/src/server/network-addresses.ts:32-40,56-67
Node binds::as dual-stack by default on supported platforms, but enumeration retains only IPv6 interfaces. The server therefore accepts IPv4 connections while metadata and diagnostics omit those addresses, understating exposure and hiding usable URLs. A Windows probe reached the::listener through127.0.0.1.
Minimal correction: explicitly define the listener’sipv6Onlybehavior and enumerate both families when dual-stack is enabled. -
Medium: IPv6 link-local candidates are unusable because their scope IDs are discarded.
packages/server/src/server/network-addresses.ts:34-40,61-66
fe80::/10interfaces are classified as external and can become the primary remote URL, but theirscopeidis omitted. The resulting URLs cannot reliably identify an interface. This Windows host produced four such advertised URLs.
Minimal correction: exclude IPv6 link-local addresses from URL candidates unless a supported zone-aware representation is implemented. -
Medium: valid zero-padded IPv6 loopback forms are misclassified.
packages/server/src/server/network-host.ts:14-25
packages/server/src/server/http-server.ts:180-183
packages/server/src/index.ts:580
Valid::0001and0:0:0:0:0:0:0:0001addresses return false fromisLoopbackHost. Diagnostics label them as specific interfaces and CORS treats their loopback listener as remotely bound, allowing arbitrary origins.
Minimal correction: recognize a final IPv6 segment matching^0*1$and add both forms to host, metadata, and CORS tests. -
Low: newly exported connectivity diagnostics bypass i18n.
packages/ui/src/components/settings/info-settings-diagnostics.ts:42-62
packages/ui/src/components/settings/info-settings-section.tsx:170-180
Newly added labels, modes, scopes, and fallback values are always English, despite the localized privacy warning asking users to inspect the report before sharing it.
Minimal correction: supply translated labels and values tobuildDiagnosticReport, reusing the connectivity message keys.
Clipboard cleanup/focus restoration, metadata retry, concrete IPv4 candidates, standard compact/expanded IPv6 URLs, listener host binding, accessibility, privacy disclosure, locale parity, and focused test isolation otherwise behaved correctly.
Validation: all three commits reviewed against GitHub base 67cb394e; 18 focused server tests and 8 focused UI tests passed; server/UI typechecks and UI production build passed; direct Windows TLS, dual-stack, link-local, and padded-loopback probes reproduced the findings; git diff --check passed. The full server suite had only the specified unrelated git-worktrees.test.ts assertion failure. GitHub Linux tests pass; the current Windows failure is in an unchanged Tauri cross-host test and is not PR-caused.
Make IPv6 wildcard listeners explicitly dual-stack, omit unusable link-local candidates, and recognize zero-padded loopback forms so reported addresses match effective reachability. Regenerate generated TLS certificates when the active host or configured SANs are missing, including IPv6 loopback coverage for wildcard listeners. Localize every exported diagnostic report label and add focused regression coverage. Validated with focused server and UI tests, server/root typechecks, the UI production build, and git diff checks.
pascalandr
left a comment
There was a problem hiding this comment.
Gatekeeper review - FAIL
-
Medium: IPv4-mapped IPv6 hosts are misclassified.
packages/server/src/server/network-host.ts:8-25
packages/server/src/server/network-addresses.ts:32-45
packages/server/src/index.ts:553-585Canonical forms such as
::ffff:0:0and::ffff:7f00:1bind as IPv4 wildcard and loopback addresses, but the helpers classify them as concrete external IPv6 hosts. Diagnostics can understate wildcard exposure, label loopback as external, and advertise an unusable wildcard URL. Normalize IPv4-mapped addresses before classification and add canonical-form coverage. -
Medium: certificate reuse repeatedly rotates certificates for valid host inputs.
packages/server/src/server/tls.ts:255-291
packages/server/src/server/network-host.ts:28-30Non-ASCII DNS hosts such as
münchen.localand scoped IPv6 hosts such asfe80::1%12regenerate the generated leaf certificate on every startup. Normalize DNS values withdomainToASCII()and reject or explicitly normalize zone-scoped IPv6 hosts before URL and SAN generation.
Validation: 29 focused tests, root/server typechecks, nine-locale parity, and git diff --check passed. Linux CI passed. Windows CI failed in an unchanged Tauri cross-host election test; build and artifact publication were consequently skipped/failed. The refocused #130 diagnostics scope is otherwise fulfilled.
Canonicalize IPv4-mapped IPv6 bind addresses before listener classification so wildcard exposure, loopback scope, plugin URLs, and diagnostics reflect the effective IPv4 endpoint. Convert internationalized DNS names to ASCII for stable generated certificate reuse. Reject zone-scoped IPv6 CLI hosts because they cannot form supported listener URLs, while normalizing scoped SAN entries to their certificate-safe address. Covered mapped wildcard and loopback forms, IDN certificate reuse, scoped SANs, and CLI host validation with focused tests. Server/root typechecks and diff checks pass.
pascalandr
left a comment
There was a problem hiding this comment.
Gatekeeper re-review - PASS
No actionable findings.
The previously reported findings are resolved, including IPv4-mapped IPv6 classification, IDN and scoped-IPv6 certificate reuse, dual-stack diagnostics, required-SAN certificate rotation, localization, privacy, accessibility, and issue #130 scope.
Validation covered the complete diff from 67cb394e through e8e2b5cb. Typechecks, the UI build, focused tests, and git diff --check passed. GitHub Linux and Windows/Tauri test jobs pass; build and artifact jobs are still running with no failures currently reported.
|
PR builds are available as GitHub Actions artifacts: https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/31391698012 Artifacts expire in 7 days.
|
Summary
Scope
This deliberately keeps server configuration read-only. It improves discoverability and troubleshooting in Electron, Tauri, and remote web sessions without exposing raw CLI arguments or weakening desktop listener/authentication invariants.
The Remote Access shortcut is shown only in a local desktop window; all diagnostic details come from the existing cross-platform
/api/metacontract.Validation
npm run typechecknpm run build --workspace @codenomad/uinode --import tsx --test packages/ui/src/components/settings/info-settings-diagnostics.test.ts packages/ui/src/lib/server-meta.test.tsgit diff --checkCloses #130